class Computed {
  constructor(vm, computed, key) {
    /**
         * 
         * total() {
              console.log("computedcomputed");
                return this.a + this.b;
             },
     *    {
     *      key:total,
     *      value:3,
     *      get: tatal fn
     *      dep:[a,b]  //更新的时候执行__set__回调函数  对比依赖中有没有key 
     *                  有key执行get方法
     * }
     *  */
    this.computedData = [];
  }
  // vm get中 执行vm中的 a,b
  addComputed(vm, computed, key) {
    const descriptor = Object.getOwnPropertyDescriptor(computed, key),
      descriptorFn = descriptor.value.get //computed写法 get() 或者直接写
        ? descriptor.value.get
        : descriptor.value,
      value = descriptorFn.bind(vm)(),
      get = descriptorFn.bind(vm),
      dep = this._colletDep(descriptorFn);
    this._addComputedProp({
      key,
      value,
      get,
      dep,
    });

    const dataItem = this.computedData.find((item) => item.key === key);
    console.log(dataItem, value);
    Object.defineProperty(vm, key, {
      get() {
        console.log("get get ", key);
        return dataItem.value;
      },
      set(newValue) {
        dataItem.value = dataItem.get();
        console.log("set set ", key, newValue);
      },
    });

    // 这样定义 computed做不到响应式
    // Object.defineProperty(vm, key, {
    //   get() {
    //     return value;
    //   },
    // });
  }
  _addComputedProp(computedProp) {
    this.computedData.push(computedProp);
  }

  // data中的数据发生改变时 执行
  update(key, watch) {
    console.log("computed中的 update", key);
    this.computedData.forEach((item) => {
      const dep = item.dep;
      const _key = dep.find((el) => el === key);
      // 依赖里存在 就重新执行 get方法

      if (_key) {
        const oldValue = item.value;
        item.value = item.get();
        watch(item.key, item.value, oldValue);
      }
    });
  }

  _colletDep(fn) {
    const matched = fn.toString().match(/this\.(.+?)/g);
    let dep = matched.map((item) => item.split(".")[1]);
    return Array.from(new Set(dep)); // 为什么要去重？变量重复使用？？
  }
}

export { Computed };
